// // Copyright (c) 2009 All Right Reserved // // vl // // 2009-01-01 // Contains ... using System; using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics.Contracts; using System.Linq; using System.Text; using System.Xml.Serialization; using JetBrains.Annotations; using LargoCommon.Abstract; using LargoCommon.Interfaces; namespace LargoCommon.Music { /// /// Variety of structures. /// /// Structure - the generic type parameter. /// /// Variety represents variety of structures, modalities or other patterns inside /// of a given GSystem. It is used as a common superclass for harmonic and rhythmical system varieties. /// [Serializable] [XmlInclude(typeof(HarmonicSystem))] [XmlInclude(typeof(RhythmicSystem))] [XmlInclude(typeof(MelodicSystem))] [XmlInclude(typeof(HarmonicStructure))] [XmlInclude(typeof(RhythmicStructure))] [XmlInclude(typeof(MelodicStructure))] public class StructuralVariety where T : class, IGeneralStruct, IModalStruct, new() { #region Fields /// Array of structures. private List structList; //// readonly /// /// General system. /// private GeneralSystem gsystem; //// readonly /// /// Special numbers. /// private byte n2, n3, n4, n6; #endregion #region Constructors /// /// Initializes a new instance of the StructuralVariety class. Serializable. /// /// The given system. public StructuralVariety(GeneralSystem givenSystem) { // : base() this.structList = new List(); this.GSystem = givenSystem; } /// /// Prevents a default instance of the class from being created. /// private StructuralVariety() { } #endregion #region Properties /// Gets or sets modality of structures. /// Property description. [XmlIgnore] public BinaryStructure Modality { get; set; } /// Gets array of structures. /// Property description. [XmlIgnore] public Collection StructList { get { Contract.Ensures(Contract.Result>() != null); if (this.structList == null) { throw new InvalidOperationException("List of structures is null."); } return new Collection(this.structList); } //// set { this.structList = value; } } /// Gets or sets qualifier. /// Property description. public GeneralQualifier Qualifier { private get; set; } /// Gets or sets maximum number of structures. /// Property description. public int LimitCount { private get; set; } /// Gets or sets type of variety. /// Property description. public StructuralVarietyType VarType { private get; set; } /// Gets or sets abstract G-System. /// Property description. [XmlIgnore] private GeneralSystem GSystem { get { Contract.Ensures(Contract.Result() != null); return this.gsystem ?? new GeneralSystem(); } set => this.gsystem = value ?? throw new ArgumentException("Argument cannot be empty.", nameof(value)); } #endregion #region String representation /// String representation of the object. /// Returns value. public override string ToString() { var s = new StringBuilder(); if (this.Qualifier != null) { s.Append(this.Qualifier); } //// if (this.StructList == null) { return s.ToString(); } foreach (var bs in this.StructList) { s.Append(bs); } return s.ToString(); } #endregion /// /// Sets the struct list. /// /// The list. [UsedImplicitly] public void SetStructList(IEnumerable list) { Contract.Requires(list != null); this.structList = list.ToList(); } /// Returns the next optimal harmonic structure. /// General musical request. /// Returns value. [UsedImplicitly] public T OptimalNextStructForRequest(GeneralRequest givenRequest) { var optimalStruct = default(T); var extremeTotal = -10000000f; foreach (var str in this.StructList) { str.WriteBehaviorToProperties(); var total = str.SumForRequest(givenRequest); if (total <= extremeTotal) { continue; } extremeTotal = total; optimalStruct = str; } if ((optimalStruct == null) && (this.StructList.Count > 0)) { optimalStruct = this.StructList[0]; } return optimalStruct; } /// Generate all instances of structures. /// Requested level. /// Returns value. [UsedImplicitly] public bool GenerateInstances(byte givenLevel) { var r = (decimal)Math.Pow(this.GSystem.Degree, this.GSystem.Order) - 1; for (decimal num = 1; num <= r; num++) { var level = FiguralStructure.DetermineLevel(this.GSystem.Order, num); if (level == givenLevel) { this.AddStructure(num); } if (this.StructList.Count >= this.LimitCount) { break; } } return this.StructList.Count > 0; } /// Generate all classes, i.e. representatives of structures (without transpositions). /// Requested level. /// Returns value. [UsedImplicitly] public bool GenerateClasses(byte givenLevel) { const int maxSize = 1000000; var rsize = (decimal)Math.Pow(this.GSystem.Degree, this.GSystem.Order) - 1; var r = (int)Math.Min(rsize, maxSize); if (r < 0) { return false; } var marked = new BitArray(r + 1, false); // bool[] marked = new bool[r+1]; //// for (g=this.GSystem.Degree; g<= r; g+=this.GSystem.Degree) marked.Set(g,true); var g = 1; while (g <= r) { if (g < marked.Count && !marked.Get(g)) { // !marked[g] if (this.StructList.Count >= this.LimitCount) { return true; //// Avoid multiple or conditional return statements. } decimal gl = g; var level = FiguralStructure.DetermineLevel(this.GSystem.Order, gl); if (givenLevel == level) { this.AddStructure(gl); } this.MarkInstancesOfClass(rsize, r, marked, g); } g = g + 1; } return this.StructList.Count > 0; } /// Generate all classes, i.e. representatives of structures (without transpositions). /// Requested level. /// Returns value. [UsedImplicitly] public bool GenerateBinaryClasses(byte givenLevel) { var r = (long)Math.Pow(this.GSystem.Degree, this.GSystem.Order - 1) - 1; long num; byte level; for (num = 1; num <= r; num += 2) { level = BinaryNumber.DetermineLevel(this.GSystem.Order, num); if (level == givenLevel) { var classNumber = BinaryNumber.DetermineClassNumber(this.GSystem.Order, num); if (num == classNumber) { this.AddStructure(num); } } if (this.StructList.Count >= this.LimitCount) { break; } } num = (long)Math.Pow(this.GSystem.Degree, this.GSystem.Order) - 1; level = BinaryNumber.DetermineLevel(this.GSystem.Order, num); if (level == givenLevel) { this.AddStructure(num); } return this.StructList.Count > 0; } /// Generate variety. public void Generate() { switch (this.VarType) { case StructuralVarietyType.Classes: this.GenerateClasses(); break; case StructuralVarietyType.Instances: this.GenerateInstances(); break; case StructuralVarietyType.BinaryClasses: this.GenerateBinaryClasses(); break; case StructuralVarietyType.BinarySubstructuresOfModality: this.GenerateBinarySubstructures(this.Modality); break; case StructuralVarietyType.FiguralSubstructuresOfModality: this.GenerateFiguralSubstructures(this.Modality); break; case StructuralVarietyType.RhythmicModalityClasses: this.GenerateRhythmicModalityClasses(); break; case StructuralVarietyType.RhythmicMetricClasses: this.GenerateMetricClasses(); break; case StructuralVarietyType.None: break; case StructuralVarietyType.MelodicStructuresOfModality: break; //// resharper default: break; } this.structList?.Sort(); } /// Sort array of structures with regard to given item. /// General musical property. /// Sort direction. public void SortStructList(GenProperty property, GenSortDirection givenDirection) { var comparer = new ComparerGenStruct(property, givenDirection); this.structList?.Sort(0, this.StructList.Count, comparer); } #region Private static /// /// Is Valid Composed Schema. /// /// Schema of the structure. /// Returns value. private static bool IsValidComposedSchema(IList schema) { Contract.Requires(schema != null); var status = schema != null; return status; } #endregion #region Private /// /// Marks the instances of class. /// /// The r-system size. /// The r. /// The marked. /// The g. private void MarkInstancesOfClass(decimal rsize, int r, BitArray marked, int g) { var u = g; while (u != 0 && u < r && u > 0 && u < marked.Count && !marked.Get(u)) { // marked[u] if (u < marked.Count) { marked.Set(u, true); // marked[u]=true; } //// time optimization of u = (int)((decimal)(u*this.GSystem.Degree) % rsize); decimal ul = u; //// if (this.GSystem.Degree == 2) { ((long)ul) <<= 1; } else { ul *= this.GSystem.Degree; //// } while (ul > rsize) { ul -= rsize; } u = (int)ul; } } /// Creates structures Y as substructures of X. /// Number of master structure. /// Bit to start with. /// Number of not finished bits. /// Resulting structure. /// Returns value. [UsedImplicitly] private bool RecursiveAdd(FiguralNumber structureX, byte fromBit, byte restBits, FiguralNumber structureY) { //// cyclomatic complexity 10:11 Contract.Requires(structureX != null); if (structureX == null) { return false; } var fsX = new FiguralNumber(structureX); if (this.StructList.Count >= this.LimitCount || structureY == null) { return false; } if (restBits == 0) { this.AppendStructureFromNumber(structureY); } else { // Yet > 0 for (var j = fromBit; j < this.GSystem.Order; j++) { if (!structureX.IsOn(j)) { continue; // j in aNumX } structureX.SetElement(j, 0); // aNumX - [j] for (byte d = 1; d < this.GSystem.Degree; d++) { structureY.SetElement(j, d); // aNumY + [j] byte nextRestBits; checked { nextRestBits = (byte)(restBits - 1); } if (!this.RecursiveAdd(fsX, j, nextRestBits, structureY)) { return false; //// Avoid multiple or conditional return statements. } structureY.SetElement(j, 0); // aNumY - [j] } } } return true; } /// /// Appends the structure from number. /// /// The structure Y. private void AppendStructureFromNumber(FiguralNumber structureY) { Contract.Requires(structureY != null); structureY.DetermineINumber(); if (structureY.DecimalNumber <= 0) { return; } var figStruct = this.CreateStructure(structureY.DecimalNumber); //// typeof(FiguralStructure) var ok1 = !figStruct.IsEmptyStruct(); if (!ok1) { return; } var ok2 = this.Convenient(figStruct); if (ok2) { this.StructList.Add(figStruct); } } #endregion #region Generation of substructures /// Returns if Qualifier allows adding of this structure. /// General musical structure. /// Returns value. [UsedImplicitly] private bool Convenient(IGeneralStruct generalStructure) { if (generalStructure == null || generalStructure.IsEmptyStruct()) { return false; } if (!generalStructure.IsValidStruct()) { return false; } return this.Qualifier == null || this.Qualifier.Convenient(generalStructure); } /// Generate all substructures of the given modality. /// Abstract modality. /// Returns value. [UsedImplicitly] private bool GenerateBinarySubstructures(IGeneralStruct modality) { if (modality == null) { return false; } byte level = modality.Level, lev; var emptyNum = 0L; // 0x00000000; BinaryStructure.BitAt(0); for (lev = 0; lev <= level; lev++) { if (this.StructList.Count >= this.LimitCount) { break; } this.RecursiveAdd((long)modality.DecimalNumber, 0, lev, ref emptyNum); } return this.StructList.Count > 0; } #endregion #region Generation of figural substructures /// /// Generate all substructures of the given modality. /// /// Abstract modality. private void GenerateFiguralSubstructures(BinaryStructure modality) { if (modality == null) { return; } byte level = modality.Level, lev; var emptyStruct = new FiguralNumber(this.GSystem, 0); for (lev = 0; lev <= level; lev++) { if (this.StructList.Count >= this.LimitCount) { break; } var figuralModality = new FiguralStructure(this.GSystem, 0); for (byte j = 0; j < this.GSystem.Order; j++) { figuralModality.SetElement(j, (byte)(modality.IsOn(j) ? 1 : 0)); } //// RecursiveAdd(fsModality,0,lev,emptyStruct); this.RecursiveAdd(modality, 0, lev, emptyStruct); } } #endregion #region Generation of instances /// /// Generate all instances of structures. /// private void GenerateInstances() { var r = (decimal)Math.Pow(this.GSystem.Degree, this.GSystem.Order) - 1; for (decimal num = 1; num <= r; num++) { this.AddStructure(num); if (this.StructList.Count >= this.LimitCount) { break; } } } #endregion #region Generation of classes /// /// Generate all classes, i.e. representatives of structures (without transpositions). /// private void GenerateClasses() { const int maxSize = 1000000; var rsize = (decimal)Math.Pow(this.GSystem.Degree, this.GSystem.Order) - 1; var r = (int)Math.Min(rsize, maxSize); if (r < 0) { return; } var marked = new BitArray(r + 1, false); // bool[] marked = new bool[r+1]; ///// for (g=this.GSystem.Degree; g<= r; g+=this.GSystem.Degree) marked.Set(g,true); var g = 1; while (g <= r) { if (g < marked.Count && !marked.Get(g)) { // !marked[g] if (this.StructList.Count >= this.LimitCount) { return; } decimal gl = g; //// // // byte level = BinaryStructure.DetermineLevel(this.GSystem.Order, gl); this.AddStructure(gl); this.MarkInstancesOfClass(g, r, marked); } g = g + 1; } } /// /// Marks the instances of class. /// /// The g. /// The r. /// The marked. private void MarkInstancesOfClass(int g, int r, BitArray marked) { var u = g; while (u != 0 && u < r && u > 0 && u < marked.Count && !marked.Get(u)) { // marked[u] if (u < marked.Count) { marked.Set(u, true); // marked[u]=true; } //// // time optimization of u = (int)((decimal)(u*this.GSystem.Degree) % rsize); decimal ul = u; //// if (this.GSystem.Degree == 2) { ((long)ul) <<= 1; } else { ul *= this.GSystem.Degree; //// } while (ul > r) { ul -= r; } u = (int)ul; } } /// /// Generate all classes, i.e. representatives of structures (without transpositions). /// private void GenerateBinaryClasses() { var r = (decimal)Math.Pow(this.GSystem.Degree, this.GSystem.Order - 1) - 1; long num; for (num = 1; num <= r; num += 2) { decimal classNumber = BinaryNumber.DetermineClassNumber(this.GSystem.Order, num); if (num == classNumber) { this.AddStructure(num); } if (this.StructList.Count >= this.LimitCount) { break; } } num = (long)Math.Pow(this.GSystem.Degree, this.GSystem.Order) - 1; this.AddStructure(num); } /// /// Generate all classes, i.e. representatives of structures (without transpositions). /// [ContractVerification(false)] private void GenerateRhythmicModalityClasses() { const byte divisor2 = 2; const byte divisor3 = 3; const byte divisor4 = 4; const byte divisor6 = 6; this.n2 = (byte)(this.GSystem.Order / divisor2); this.n3 = (byte)(this.GSystem.Order / divisor3); this.n4 = (byte)(this.GSystem.Order / divisor4); this.n6 = (byte)(this.GSystem.Order / divisor6); var lastIndex = (byte)(this.GSystem.Order - 1); // for k=36: 24 var r = (long)Math.Pow(this.GSystem.Degree, lastIndex) - 1; long num; for (num = 1; num <= r; num += 1) { // for k=36: += 2 if (this.GSystem.Order > DefaultValue.HarmonicOrder) { // 8 if (!this.IsSeparableStructure(num)) { continue; } } var classNumber = BinaryNumber.DetermineClassNumber(this.GSystem.Order, num); if (num == classNumber) { this.AddValidRhythmicModalitySchema(num); return; } if (this.StructList.Count >= this.LimitCount) { break; } } num = (long)Math.Pow(this.GSystem.Degree, this.GSystem.Order) - 1; this.AddStructure(num); } /// /// Adds the valid rhythmic modality schema. /// /// The number. private void AddValidRhythmicModalitySchema(long num) { var schema = BinaryNumber.DistSchema(this.GSystem.Order, num); var lev = (byte)schema.Count; if ((this.GSystem.Order >= (byte)RhythmicOrder.R24) && (lev > 8)) { return; } var lastIndex = (byte)(lev - 1); var lastElement = schema[lastIndex]; var status = this.GSystem.Order <= DefaultValue.HarmonicOrder || IsValidComposedSchema(schema); //// Simplicity condition if (status) { status = this.IsSimpleSchema(lastIndex, schema, lev, lastElement); } if (!status) { return; } this.AddStructure(num); } #endregion /// Creates on structure. /// Number of instance. /// Returns value. private T CreateStructure(decimal number) { //// Type type //// Contract.Requires(type != null); var obj = (T)Activator.CreateInstance(typeof(T), this.GSystem, number); //// T obj = new T { GSystem = this.GSystem, Modality = this.Modality, DecimalNumber = number }; obj.DetermineBehavior(); return obj; // default(T) } /// Creates structures Y as substructures of X. /// Master structure. /// Bit to start with. /// Number of not finished bits. /// Resulting structure. /// Returns value. private bool RecursiveAdd(BinaryStructure structureX, byte fromBit, byte restBits, FiguralNumber structureY) { Contract.Requires(structureX != null); var fsX = new BinaryStructure(structureX); if (this.StructList.Count >= this.LimitCount || structureY == null) { return false; } if (restBits == 0) { structureY.DetermineINumber(); if (structureY.DecimalNumber <= 0) { return true; } var figStruct = this.CreateStructure(structureY.DecimalNumber); //// typeof(FiguralStructure) var ok1 = !figStruct.IsEmptyStruct() && figStruct.IsValidStruct(); if (!ok1) { return true; } var ok2 = this.Convenient(figStruct); if (ok2) { this.StructList.Add(figStruct); } } else { // Yet > 0 for (var j = fromBit; j < this.GSystem.Order; j++) { if (!fsX.IsOn(j)) { continue; // j in aNumX } fsX.Off(j); // aNumX - [j] for (byte d = 1; d < this.GSystem.Degree; d++) { structureY.SetElement(j, d); // aNumY + [j] byte nextRestBits; checked { nextRestBits = (byte)(restBits - 1); } if (!this.RecursiveAdd(fsX, j, nextRestBits, structureY)) { return false; //// Avoid multiple or conditional return statements. } structureY.SetElement(j, 0); // aNumY - [j] } } } return true; } /// /// Creates structures Y as substructures of X. /// /// Number of master structure. /// Bit to start with. /// Number of not finished bits. /// Resulting structure. /// /// Returns value. /// private bool RecursiveAdd(long numberX, byte fromBit, byte restBits, ref long numberY) { if (this.StructList.Count >= this.LimitCount) { return false; } if (restBits == 0) { if (numberY <= 0) { return true; } var str = this.CreateStructure(numberY); //// typeof(BinaryStructure) var ok1 = !str.IsEmptyStruct(); if (!ok1) { return true; } var ok2 = this.Convenient(str); if (ok2) { this.StructList.Add(str); } } else { // Yet > 0 var order = this.GSystem.Order; for (var j = fromBit; j < order; j++) { if ((numberX & BinaryNumber.BitAt(j)) == (decimal)0) { continue; // j in aNumX } numberX = numberX & BinaryNumber.NotBitAt(j); // aNumX - [j] numberY = numberY | BinaryNumber.BitAt(j); // aNumY + [j] if (!this.RecursiveAdd(numberX, j, (byte)(restBits - 1), ref numberY)) { return false; //// Avoid multiple or conditional return statements. } numberY = numberY & BinaryNumber.NotBitAt(j); // aNumY - [j]; } } return true; } /// /// Generate all metric classes, i.e. symmetric representatives of structures. /// private void GenerateMetricClasses() { var order = this.GSystem.Order; for (byte d = 1; d <= order; d++) { if (order % d != 0) { continue; } var bs = new BinaryNumber(this.GSystem, 0); for (byte e = 0; e < order; e += d) { bs.On(e); } this.AddStructure(bs.Number); } } /// /// Is Separable Structure. /// /// Structural Number. /// Returns value. private bool IsSeparableStructure(long num) { var level = BinaryNumber.DetermineLevel(this.GSystem.Order, num); if (level <= 4) { return true; } if (!BinaryNumber.ElementIsOn(num, this.n2)) { return false; } if (this.GSystem.Order == 16) { if (!BinaryNumber.ElementIsOn(num, this.n4)) { return false; //// Avoid multiple or conditional return statements. } } else { if (!(BinaryNumber.ElementIsOn(num, this.n3) || BinaryNumber.ElementIsOn(num, this.n4) || BinaryNumber.ElementIsOn(num, this.n6))) { return false; //// Avoid multiple or conditional return statements. } } return true; } /// Add modality with given number to array of structures. /// Number of instance. private void AddStructure(decimal number) { var obj = this.CreateStructure(number); //// typeof(T) var ok = this.Convenient(obj); if (ok) { this.StructList.Add(obj); } } /// /// Determines whether [is simple schema] [the specified last index]. /// /// The last index. /// The schema. /// The level. /// The last element. /// /// True if [is simple schema] [the specified last index]; otherwise, false. /// private bool IsSimpleSchema(byte lastIndex, IList schema, byte level, byte lastElement) { Contract.Requires(schema != null); if (this.GSystem.Order <= 16 || level <= 3) { return true; //// originally 8 but failed 313144 !? in 16 } var status = true; for (byte j = 0; j < lastIndex; j++) { var elem = schema[j]; if ((lastElement % elem == 0) || MathSupport.GreatestCommonDivisor(lastElement, elem) != 1) { continue; } status = false; break; } return status; } } }